using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Xml;
using GGEditor.API;
using GGEditor.API.Plugins;

namespace GGEditor.Core.Plugins
{
	public class XmlNodeObjectFactory : IXmlNodeObjectFactory
	{
		private readonly static XmlNodeObjectFactory instance =
			new XmlNodeObjectFactory();

		private readonly IDictionary<string, IXmlNodeObjectFactory> factories =
			new Dictionary<string, IXmlNodeObjectFactory>();

		private XmlNodeObjectFactory() { }

		public static XmlNodeObjectFactory Instance
		{
			get { return instance; }
		}

		public void Register(string className, IXmlNodeObjectFactory factory)
		{
			factories[className] = factory;
		}

		public void RegisterFromAssembly(Assembly assembly)
		{
			foreach (Type type in assembly.GetTypes())
			{
				string tagName = "";

				if (!type.IsClass)
					continue;

				if (!typeof(IXmlNodeObjectFactory).IsAssignableFrom(type))
					continue;

				foreach (object attribute in type.GetCustomAttributes(false))
				{
					if (attribute is XmlNodeObjectFactoryAttribute)
						tagName = (attribute as XmlNodeObjectFactoryAttribute).Name;
				}

				if (tagName == "")
					continue;

				object o = Activator.CreateInstance(type);
				Register(tagName, o as IXmlNodeObjectFactory);
			}
		}

		public IXmlNodeObjectFactory GetFactory(string className)
		{
			if (!factories.ContainsKey(className))
				throw new InvalidDataException(
					string.Format("Object of class \"{0}\" cannot be built (unknown)",
					              className));
			return factories[className];
		}

		#region Implementation of IXmlNodeObjectFactory

		public object Build(IPluginNode pluginNode, IDictionary<string, string> attributes)
		{
			IXmlNodeObjectFactory factory = GetFactory(pluginNode.Class);
			return factory.Build(pluginNode, attributes);
		}

		#endregion
	}
}